/*
 * Copyright (c) China Telecom Cloud Technology Co., Ltd. 2024-2025. All rights reserved.
 */
#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <functional>
#include <future>
#include <mutex>
#include <queue>
#include <thread>
#include <utility>
#include <vector>

#include "SafeQueue.h"

class ThreadPool {
private:
    class ThreadWorker {
    private:
        int _id;
        ThreadPool *_pool;

    public:
        /**
         *! @brief 创建一个工作线程对象
         * 
         * @param pool 工作对象隶属的线程池
         * @param id   工作对象id
         */
        ThreadWorker(ThreadPool *pool, const int id);


        /**
         *! @brief 从工作任务队列中不断取出任务并执行
         * 
         */
        void operator()();
    }; // ThreadWorker()

    bool _shutdown;                           // 线程池是否已经关闭

    SafeQueue<std::function<void()>> _queue;  // 用于存放待运行的函数
    std::vector<std::thread> _threads;        // 多个线程(轮流去队列中取出运行任务并运行)
    std::mutex               _mutex;          // 基础的多线程互斥锁
    std::condition_variable  _has_task;       // 等待有任务的条件变量

public:
    ThreadPool(const int n_threads);

    ~ThreadPool();

    //! 禁用拷贝、赋值、移动构造函数
    ThreadPool(const ThreadPool &)            = delete;
    ThreadPool(ThreadPool &&)                 = delete;
    ThreadPool &operator=(const ThreadPool &) = delete;
    ThreadPool &operator=(ThreadPool &&)      = delete;


    /**
     *! @brief 初始化，将每个线程绑定一个ThreadWorker，循环从任务队列中取任务并执行
     * 
     */
    void init();


    /**
     *! @brief 关闭线程池(有工作的需要先完成)
     * 
     */
    void shutdown();


    /**
     *! @brief 向线程池中提交一个函数，并异步执行
     * 
     * @tparam F     函数类型模板
     * @tparam Args  函数参数类型(可变)
     * @param f      函数实例
     * @param args   函数参数
     * 
     * @return std::future<decltype(f(args...))>  返回future对象
     */
    template <typename F, typename... Args>
    auto submit(F &&f, Args &&...args) -> std::future<decltype(f(args...))> {
        // 通过函数与参数绑定，形成一个无参的偏函数
        std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), 
                                                    std::forward<Args>(args)...);

        // 把“可调用对象”转成“可异步执行的任务”，并赠送一个 std::future 用来在未来某个时刻同步地拿到结果或异常。
        auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);

        // Wrap packaged task into void function
        std::function<void()> wrapper_func = [task_ptr]() {
            (*task_ptr)();
        };

        // 向队列中添加该执行任务
        _queue.enqueue(wrapper_func);

        // 唤醒一个没有任务执行正在休眠的线程
        _has_task.notify_one();

        // 从promise对象获取future对象，后续可以从该future对象获取函数的运行结果
        return task_ptr->get_future();
    }
};
#endif // THREADPOOL_H